#include "EngineOpenGL.h"

void GC(const char* cause)
{
	GLenum err;
	while((err=glGetError())!=GL_NO_ERROR)
	{
		const char* msg;
		switch(err)
		{
		case GL_INVALID_ENUM:
			msg = "GL_INVALID_ENUM";
			break;
		case GL_INVALID_VALUE:
			msg = "GL_INVALID_VALUE";
			break;
		case GL_INVALID_OPERATION:
			msg = "GL_INVALID_OPERATION";
			break;
		case GL_INVALID_FRAMEBUFFER_OPERATION:
			msg = "GL_INVALID_FRAMEBUFFER_OPERATION";
			break;
		}
		printf("%s ERROR: %s\n",cause,msg);
	}
}

EngineOpenGL::EngineOpenGL(LPCSTR title)
	:EngineWin32(title)
{
	//init opengl & glew
	
	PIXELFORMATDESCRIPTOR pfd;
	ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR));
	pfd.nSize			= sizeof(PIXELFORMATDESCRIPTOR);
	pfd.nVersion		= GL_VERSION_2_0;
	pfd.dwFlags			= PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
	pfd.iPixelType		= PFD_TYPE_RGBA;
	pfd.cColorBits		= 24;
	pfd.cDepthBits		= 32;
	pfd.iLayerType		= PFD_MAIN_PLANE;

	hdc = GetDC(hwnd);
	int  iPixelFormat; 
	iPixelFormat = ChoosePixelFormat(hdc, &pfd); 
	SetPixelFormat(hdc, iPixelFormat, &pfd);
	hglrc = wglCreateContext(hdc);
	wglMakeCurrent(hdc,hglrc);

	GLenum err = glewInit();

	//init shader

	int slen;
	GLchar* ssrc;
	int ssucc;

	ReadFile("vsTransform.glsl",&slen,NULL);
	ssrc = new GLchar[slen+1];
	ReadFile("vsTransform.glsl",&slen,ssrc);
	ssrc[slen] = 0;
	_vs = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(_vs,1,(const GLchar**)&ssrc,NULL);
	glCompileShader(_vs);
	delete[] ssrc;
	glGetShaderiv(_vs,GL_COMPILE_STATUS,&ssucc);
	if(ssucc!=GL_TRUE)
	{
		char log[1024];
		glGetShaderInfoLog(_vs,1024,NULL,log);
		printf("%s\n",log);
	}

	ReadFile("fsDraw.glsl",&slen,NULL);
	ssrc = new GLchar[slen+1];
	ReadFile("fsDraw.glsl",&slen,ssrc);
	ssrc[slen] = 0;
	_fs = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(_fs,1,(const GLchar**)&ssrc,NULL);
	glCompileShader(_fs);
	delete[] ssrc;
	glGetShaderiv(_fs,GL_COMPILE_STATUS,&ssucc);
	if(ssucc!=GL_TRUE)
	{
		char log[1024];
		glGetShaderInfoLog(_fs,1024,NULL,log);
		printf("%s\n",log);
	}

	_prog = glCreateProgram();
	glAttachShader(_prog,_vs);
	glAttachShader(_prog,_fs);
	glLinkProgram(_prog);
	glGetProgramiv(_prog,GL_LINK_STATUS,&ssucc);
	if(ssucc!=GL_TRUE)
	{
		char log[1024];
		glGetProgramInfoLog(_prog,1024,NULL,log);
		printf("%s\n",log);
	}

	glUseProgram(_prog);

	//default settings

	glClearColor(0.5f,0.5f,0.5f,1.0f);
	glClearDepth(1.0);
	glEnable(GL_DEPTH_TEST);

	//build geometry
	
	int vlen;
	int ilen;
	GenGeometryRhom(&vlen,&ilen,NULL,NULL,NULL);
	float* pos = new float[vlen*3];
	float* color = new float[vlen*3];
	int* index = new int[ilen];
	GenGeometryRhom(&vlen,&ilen,pos,color,index);

	glGenBuffers(3,_VBO);
	glBindBuffer(GL_ARRAY_BUFFER,_VBO[0]);
	glBufferData(GL_ARRAY_BUFFER,sizeof(float)*vlen*3,pos,GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER,_VBO[1]);
	glBufferData(GL_ARRAY_BUFFER,sizeof(float)*vlen*3,color,GL_STATIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_VBO[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(int)*ilen,index,GL_STATIC_DRAW);

	GC("init");
}

EngineOpenGL::~EngineOpenGL()
{

}

float angle = 0.0f;

void EngineOpenGL::Redraw()
{
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	float mt[16];
	float r1[16];
	GenMatrixRotateY(acosf(1.0f/sqrtf(2.0f)),r1);
	float r2[16];
	GenMatrixRotateZ(acosf(1.0f/sqrtf(3.0f)),r2);
	float r3[16];
	GenMatrixRotateY(angle,r3);
	MultiplyMatrixMatrix(r2,r1,mt);
	MultiplyMatrixMatrix(r3,mt,mt);

	float eye[4] = {10.0f,0.0f,0.0f,1.0f};
	float center[4] = {0.0f,0.0f,0.0f,1.0f};
	float top[4] = {0.0f,1.0f,0.0f,0.0f};

	float view[16];
	GenMatrixLookAt(eye,center,top,view);
	MultiplyMatrixMatrix(view,mt,mt);
	float proj[16];
	GenMatrixPerspectiveProject(3.14159f/4.0f,(float)SCREEN_WIDTH/(float)SCREEN_HEIGHT,1.0f,100.0f,proj);
	MultiplyMatrixMatrix(proj,mt,mt);

	GLint hTrans = glGetUniformLocation(_prog,"trans");
	glUniformMatrix4fv(hTrans,1,GL_TRUE,mt);

	angle += 0.02f;

	GLint hPos = glGetAttribLocation(_prog,"pos");
	GLint hColor = glGetAttribLocation(_prog,"color");

	glBindBuffer(GL_ARRAY_BUFFER,_VBO[0]);
	glVertexAttribPointer(hPos,3,GL_FLOAT,GL_FALSE,0,NULL);
	glEnableVertexAttribArray(hPos);
	GC("set vertex");
	glBindBuffer(GL_ARRAY_BUFFER,_VBO[1]);
	glVertexAttribPointer(hColor,3,GL_FLOAT,GL_FALSE,0,NULL);
	glEnableVertexAttribArray(hColor);
	GC("set color");
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_VBO[2]);
	glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_INT,NULL);
	GC("draw elements");

	glFlush();

	SwapBuffers(hdc);

}
